#pragma once

#include <linux/types.h>
#include <linux/clocksource.h>

struct clock_event_device;

/*
 * Possible states of a clock event device.
 *
 * DETACHED:	Device is not used by clockevents core. Initial state or can be
 *		reached from SHUTDOWN.
 * SHUTDOWN:	Device is powered-off. Can be reached from PERIODIC or ONESHOT.
 * PERIODIC:	Device is programmed to generate events periodically. Can be
 *		reached from DETACHED or SHUTDOWN.
 * ONESHOT:	Device is programmed to generate event only once. Can be reached
 *		from DETACHED or SHUTDOWN.
 * ONESHOT_STOPPED: Device was programmed in ONESHOT mode and is temporarily
 *		    stopped.
 */
enum clock_event_state
{
    CLOCK_EVT_STATE_DETACHED,
    CLOCK_EVT_STATE_SHUTDOWN,
    CLOCK_EVT_STATE_PERIODIC,
    CLOCK_EVT_STATE_ONESHOT,
    CLOCK_EVT_STATE_ONESHOT_STOPPED,
};

/*
 * Clock event features
 */
#define CLOCK_EVT_FEAT_PERIODIC 0x000001
#define CLOCK_EVT_FEAT_ONESHOT 0x000002
#define CLOCK_EVT_FEAT_KTIME 0x000004

#define CLOCK_EVT_FEAT_DUMMY 0x000010

struct clock_event_ops
{
    int (*set_next_event)(struct clock_event_device *, unsigned long evt);
    int (*set_next_ktime)(struct clock_event_device *, ktime_t tim);
    int (*set_state)(struct clock_event_device *, int state);
};

struct clock_event_device
{
    void (*event_handler)(struct clock_event_device *);

    const struct clock_event_ops *ops;

    unsigned long min_delta_ticks;
    unsigned long max_delta_ticks;

    ktime_t next_event;

    enum clock_event_state state_use_accessors;
    unsigned int mult;
    unsigned int features;
    u64 max_delta_ns;
    u64 min_delta_ns;
    unsigned int shift;
};

void clockevents_config_and_register(struct clock_event_device *dev,
                                     unsigned int freq, unsigned long min_delta,
                                     unsigned long max_delta);

void clockevents_register_device(struct clock_event_device *dev);

void clockevents_handle(struct clock_event_device *dev);

static inline bool clockevent_state_oneshot_stopped(struct clock_event_device *dev)
{
    return dev->state_use_accessors == CLOCK_EVT_STATE_ONESHOT_STOPPED;
}

static inline bool clockevent_state_oneshot(struct clock_event_device *dev)
{
    return dev->state_use_accessors == CLOCK_EVT_STATE_ONESHOT;
}

static inline bool clockevent_state_shutdown(struct clock_event_device *dev)
{
    return dev->state_use_accessors == CLOCK_EVT_STATE_SHUTDOWN;
}
